package com.tools.middle.elasticsearch;

import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import com.tools.common.container.OwnPairs;
import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * QueryString 多字段 query 查询
 * 继承父类的方法在多条件查询时不起作用（除了分词器）
 * */
@Note("QueryString 多字段 query 查询。" +
        "继承父类的方法在多条件查询时不起作用（除了分词器）")
public final class StringSearch extends Search implements MultiFieldInterface {

    @Note("多字段列表")
    private List<String> fields;

    @Note("要查询的内容")
    private String query;

    @Note("相差几个字符的不同依旧可以查询出来")
    private int fuzziness = 3;

    /* **********************************************************************************
     *
     *          构造器
     *
     * *********************************************************************************
     * */

    public StringSearch(String query) {
        this.setQuery(query);
    }

    public static StringSearch of(String query) {
        return new StringSearch(query);
    }

    /* **********************************************************************************
     *
     *          Getter / Setter
     *
     * *********************************************************************************
     * */

    public List<String> getNewFields() {
        return (fields == null || fields.isEmpty())
                ? new ArrayList<>()
                : new ArrayList<>(fields);
    }

    List<String> getFields() {
        return fields;
    }

    @Override
    public boolean checkFieldsIsEmpty() {
        return fields == null || fields.isEmpty();
    }

    public void setFields(String field) {
        default_fieldNotEmpty(field);
        this.fields = new ArrayList<>(1);
        this.fields.add(field);
    }

    public void setFields(String... fields) {
        if(fields == null) return;
        int length = fields.length;
        if(length == 0) return;
        this.fields = new ArrayList<>(length);
        for (String f : fields) {
            default_fieldNotEmpty(f);
            this.fields.add(f);
        }
    }

    public void setFields(Iterable<String> fields) {
        int length = default_getIterableSize(fields);
        if(length == 0) return;
        this.fields = new ArrayList<>(length);
        for (String f : fields) {
            default_fieldNotEmpty(f);
            this.fields.add(f);
        }
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        if(query == null || query.isEmpty()) throw new NullPointerException("要查询的内容为空");
        this.query = query;
    }

    public int getFuzziness() {
        return fuzziness;
    }

    public void setFuzziness(int fuzziness) {
        this.fuzziness = Math.max(fuzziness, 0);
    }

    /* **********************************************************************************
     *
     *          链式方法
     *
     * **********************************************************************************
     * */

    public StringSearch fields(String field) {
        this.setFields(field);
        return this;
    }

    public StringSearch fields(String... fields) {
        this.setFields(fields);
        return this;
    }

    public StringSearch fields(Iterable<String> fields) {
        this.setFields(fields);
        return this;
    }

    public StringSearch query(String query) {
        this.setQuery(query);
        return this;
    }

    public StringSearch fuzziness(int fuzziness) {
        this.setFuzziness(fuzziness);
        return this;
    }

    @Override
    public StringSearch indicesNames(String indicesName) {
        super.setIndicesNames(indicesName);
        return this;
    }

    @Override
    public StringSearch indicesNames(String... indicesNames) {
        super.setIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch indicesNames(Iterable<String> indicesNames) {
        super.setIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch timeout(String timeout) {
        super.setTimeout(timeout);
        return this;
    }

    @Override
    public StringSearch timeout(int timeout, Timeunit timeunit) {
        super.setTimeout(timeout, timeunit);
        return this;
    }

    @Override
    public StringSearch from(int from) {
        super.setFrom(from);
        return this;
    }

    @Override
    public StringSearch size(int size) {
        super.setSize(size);
        return this;
    }

    @Override
    public StringSearch analyzer(String analyzer) {
        super.setAnalyzer(analyzer);
        return this;
    }

    @Override
    public StringSearch sorts(String field, SortOrder order) {
        super.sorts(field, order);
        return this;
    }

    @Override
    public StringSearch sorts(Map<String, SortOrder> fieldAndOrders) {
        super.sorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch sorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.sorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch includes(String includeField) {
        super.includes(includeField);
        return this;
    }

    @Override
    public StringSearch includes(String... includeFields) {
        super.includes(includeFields);
        return this;
    }

    @Override
    public StringSearch includes(Iterable<String> includeFields) {
        super.includes(includeFields);
        return this;
    }

    @Override
    public StringSearch excludes(String excludeField) {
        super.excludes(excludeField);
        return this;
    }

    @Override
    public StringSearch excludes(String... excludeFields) {
        super.excludes(excludeFields);
        return this;
    }

    @Override
    public StringSearch excludes(Iterable<String> excludeFields) {
        super.excludes(excludeFields);
        return this;
    }

    @Override
    public StringSearch aggregations(String field, Aggregation agg) {
        super.aggregations(field, agg);
        return this;
    }

    @Override
    public StringSearch aggregations(Map<String, Aggregation> aggregations) {
        super.aggregations(aggregations);
        return this;
    }

    @Override
    public StringSearch aggregations(OwnPairs<String, Aggregation> aggregations) {
        super.aggregations(aggregations);
        return this;
    }

    @Override
    public StringSearch highlights(String field, HighlightField highlightField) {
        super.highlights(field, highlightField);
        return this;
    }

    @Override
    public StringSearch highlights(Map<String, HighlightField> highlights) {
        super.highlights(highlights);
        return this;
    }

    @Override
    public StringSearch highlights(OwnPairs<String, HighlightField> highlights) {
        super.highlights(highlights);
        return this;
    }

    /* **********************************************************************************
     *
     *          自定义方法
     *
     * *********************************************************************************
     * */

    public StringSearch addField(String field) {
        default_fieldNotEmpty(field);
        private_initFields(1);
        this.fields.add(field);
        return this;
    }


    public StringSearch addFields(String... fields) {
        int length = default_getArrayLength(fields);
        if(length == 0) return this;
        private_initFields(length);
        for (String f : fields) {
            default_fieldNotEmpty(f);
            this.fields.add(f);
        }
        return this;
    }

    public StringSearch addFields(Iterable<String> fields) {
        if(fields == null) return this;
        int size = default_getIterableSize(fields);
        if(size == 0) return this;
        private_initFields(size);
        for (String f : fields) {
            default_fieldNotEmpty(f);
            this.fields.add(f);
        }
        return this;
    }

    public StringSearch modifyFields(int index, String newField) {
        if(fields != null && !fields.isEmpty() && !default_indexCheck(index, fields.size())) this.fields.set(index, newField);
        return this;
    }

    public StringSearch clearFields() {
        if(fields != null && !fields.isEmpty()) this.fields.clear();
        return this;
    }

    public StringSearch removeField(String field) {
        if(fields != null && !fields.isEmpty()) this.fields.remove(field);
        return this;
    }

    public StringSearch removeField(int index) {
        if(fields != null && !fields.isEmpty()) this.fields.remove(index);
        return this;
    }

    public StringSearch removeFields(String... fields) {
        if(fields == null || fields.length == 0) return this;
        if(this.fields != null && !this.fields.isEmpty()) {
            for (String f : fields) this.fields.remove(f);
        }
        return this;
    }

    public StringSearch removeFields(Iterable<String> fields) {
        if(fields == null) return this;
        if(this.fields != null && !this.fields.isEmpty()) {
            for (String f : fields) this.fields.remove(f);
        }
        return this;
    }

    public String getField(int index) {
        if(fields != null && !fields.isEmpty() && !default_indexCheck(index, fields.size())) return fields.get(index);
        return null;
    }

    public boolean containsField(String field) {
        return this.fields != null && !this.fields.isEmpty() && this.fields.contains(field);
    }

    public int fieldSize() {
        return this.fields == null ? 0 : this.fields.size();
    }

    @Override
    public StringSearch addIndicesName(String indicesName) {
        super.addIndicesName(indicesName);
        return this;
    }

    @Override
    public StringSearch addIndicesNames(String... indicesNames) {
        super.addIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch addIndicesNames(Iterable<String> indicesNames) {
        super.addIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch modifyIndicesName(int index, String indicesName) {
        super.modifyIndicesName(index, indicesName);
        return this;
    }

    @Override
    public StringSearch removeIndicesName(String indicesName) {
        super.removeIndicesName(indicesName);
        return this;
    }

    @Override
    public StringSearch removeIndicesName(int index) {
        super.removeIndicesName(index);
        return this;
    }

    @Override
    public StringSearch removeIndicesNames(String... indicesNames) {
        super.removeIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch removeIndicesNames(Iterable<String> indicesNames) {
        super.removeIndicesNames(indicesNames);
        return this;
    }

    @Override
    public StringSearch addSort(String field, SortOrder order) {
        super.addSort(field, order);
        return this;
    }

    @Override
    public StringSearch addSorts(Map<String, SortOrder> fieldAndOrders) {
        super.addSorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch addSorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.addSorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch modifySort(int index, String field, SortOrder order) {
        super.modifySort(index, field, order);
        return this;
    }

    @Override
    public StringSearch clearSorts() {
        super.clearSorts();
        return this;
    }

    @Override
    public StringSearch removeSort(String field, SortOrder order) {
        super.removeSort(field, order);
        return this;
    }

    @Override
    public StringSearch removeSort(int index) {
        super.removeSort(index);
        return this;
    }

    @Override
    public StringSearch removeSorts(Map<String, SortOrder> fieldAndOrders) {
        super.removeSorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch removeSorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.removeSorts(fieldAndOrders);
        return this;
    }

    @Override
    public StringSearch addInclude(String field) {
        super.addInclude(field);
        return this;
    }

    @Override
    public StringSearch addIncludes(String... fields) {
        super.addIncludes(fields);
        return this;
    }

    @Override
    public StringSearch addIncludes(Iterable<String> fields) {
        super.addIncludes(fields);
        return this;
    }

    @Override
    public StringSearch modifyInclude(int index, String field) {
        super.modifyInclude(index, field);
        return this;
    }

    @Override
    public StringSearch clearIncludes() {
        super.clearIncludes();
        return this;
    }

    @Override
    public StringSearch removeInclude(String field) {
        super.removeInclude(field);
        return this;
    }

    @Override
    public StringSearch removeInclude(int index) {
        super.removeInclude(index);
        return this;
    }

    @Override
    public StringSearch removeIncludes(String... fields) {
        super.removeIncludes(fields);
        return this;
    }

    @Override
    public StringSearch removeIncludes(Iterable<String> fields) {
        super.removeIncludes(fields);
        return this;
    }

    @Override
    public StringSearch addExclude(String field) {
        super.addExclude(field);
        return this;
    }

    @Override
    public StringSearch addExcludes(String... fields) {
        super.addExcludes(fields);
        return this;
    }

    @Override
    public StringSearch addExcludes(Iterable<String> fields) {
        super.addExcludes(fields);
        return this;
    }

    @Override
    public StringSearch modifyExclude(int index, String field) {
        super.modifyExclude(index, field);
        return this;
    }

    @Override
    public StringSearch clearExcludes() {
        super.clearExcludes();
        return this;
    }

    @Override
    public StringSearch removeExclude(String field) {
        super.removeExclude(field);
        return this;
    }

    @Override
    public StringSearch removeExclude(int index) {
        super.removeExclude(index);
        return this;
    }

    @Override
    public StringSearch removeExcludes(String... fields) {
        super.removeExcludes(fields);
        return this;
    }

    @Override
    public StringSearch removeExcludes(Iterable<String> fields) {
        super.removeExcludes(fields);
        return this;
    }

    @Override
    public StringSearch addAgg(String field, Aggregation agg) {
        super.addAgg(field, agg);
        return this;
    }

    @Override
    public StringSearch addAggs(Map<String, Aggregation> aggs) {
        super.addAggs(aggs);
        return this;
    }

    @Override
    public StringSearch addAggs(OwnPairs<String, Aggregation> aggs) {
        super.addAggs(aggs);
        return this;
    }

    @Override
    public StringSearch clearAggs() {
        super.clearAggs();
        return this;
    }

    @Override
    public StringSearch removeAgg(String field) {
        super.removeAgg(field);
        return this;
    }

    @Override
    public StringSearch removeAgg(String... fields) {
        super.removeAgg(fields);
        return this;
    }

    @Override
    public StringSearch removeAgg(Iterable<String> fields) {
        super.removeAgg(fields);
        return this;
    }

    @Override
    public StringSearch addHighlight(String field, HighlightField highlightField) {
        super.addHighlight(field, highlightField);
        return this;
    }

    @Override
    public StringSearch addHighlights(Map<String, HighlightField> highlights) {
        super.addHighlights(highlights);
        return this;
    }

    @Override
    public StringSearch addHighlights(OwnPairs<String, HighlightField> highlights) {
        super.addHighlights(highlights);
        return this;
    }

    @Override
    public StringSearch clearHighlight() {
        super.clearHighlight();
        return this;
    }

    @Override
    public StringSearch removeHighlight(String field) {
        super.removeHighlight(field);;
        return this;
    }

    @Override
    public StringSearch removeHighlights(String... fields) {
        super.removeHighlights(fields);
        return this;
    }

    @Override
    public StringSearch removeHighlights(Iterable<String> fields) {
        super.removeHighlights(fields);
        return this;
    }

    /* **********************************************************************************
     *
     *          私有逻辑
     *
     * *********************************************************************************
     * */

    @Note("初始化字段名称列表")
    private void private_initFields(int initSize) {
        if(fields == null) this.fields = new ArrayList<>(initSize);
    }
}
